{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Problem: Write a Custom Activation Function\n",
    "\n",
    "### Problem Statement\n",
    "You are tasked with implementing a **custom activation function** in PyTorch that computes the following operation: \n",
    " \n",
    "$ \\text{activation}(x) = \\tanh(x) + x $ \n",
    "\n",
    "Once implemented, this custom activation function will be used in a simple linear regression model.\n",
    "\n",
    "### Requirements\n",
    "1. **Custom Activation Function**:\n",
    "   - Implement a class `CustomActivationModel` inheriting from `torch.nn.Module`.\n",
    "   - Define the `forward` method to compute the activation function \\( \\text{tanh}(x) + x \\).\n",
    "\n",
    "2. **Integration with Linear Regression**:\n",
    "   - Use the custom activation function in a simple linear regression model.\n",
    "   - The model should include:\n",
    "     - A single linear layer.\n",
    "     - The custom activation function applied to the output of the linear layer.\n",
    "\n",
    "### Constraints\n",
    "- The custom activation function should not have any learnable parameters.\n",
    "- Ensure compatibility with PyTorch tensors for forward pass computations.\n",
    "\n",
    "<details>\n",
    "  <summary>💡 Hint</summary>\n",
    "  Some details: https://stackoverflow.com/questions/55765234/pytorch-custom-activation-functions\n",
    "</details>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Generate synthetic data\n",
    "torch.manual_seed(42)\n",
    "X = torch.rand(100, 1) * 10  # 100 data points between 0 and 10\n",
    "y = 2 * X + 3 + torch.randn(100, 1)  # Linear relationship with noise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [100/1000], Loss: 1.0552\n",
      "Epoch [200/1000], Loss: 0.8031\n",
      "Epoch [300/1000], Loss: 0.7150\n",
      "Epoch [400/1000], Loss: 0.6826\n",
      "Epoch [500/1000], Loss: 0.6705\n",
      "Epoch [600/1000], Loss: 0.6659\n",
      "Epoch [700/1000], Loss: 0.6642\n",
      "Epoch [800/1000], Loss: 0.6635\n",
      "Epoch [900/1000], Loss: 0.6632\n",
      "Epoch [1000/1000], Loss: 0.6632\n"
     ]
    }
   ],
   "source": [
    "# Define the Linear Regression Model within a CustomActivationModel class\n",
    "class CustomActivationModel(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(CustomActivationModel, self).__init__()\n",
    "        self.linear = nn.Linear(1, 1)  # Single input and single output\n",
    "\n",
    "    def custom_activation(self, x):\n",
    "        return torch.tanh(x) + x\n",
    "\n",
    "    def forward(self, x):\n",
    "        return self.custom_activation(self.linear(x))\n",
    "\n",
    "# Initialize the model, loss function, and optimizer\n",
    "model = CustomActivationModel()\n",
    "criterion = nn.MSELoss()\n",
    "optimizer = optim.SGD(model.parameters(), lr=0.01)\n",
    "\n",
    "# Training loop\n",
    "epochs = 1000\n",
    "for epoch in range(epochs):\n",
    "    # Forward pass\n",
    "    predictions = model(X)\n",
    "    loss = criterion(predictions, y)\n",
    "\n",
    "    # Backward pass and optimization\n",
    "    optimizer.zero_grad()\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    "\n",
    "    # Log progress every 100 epochs\n",
    "    if (epoch + 1) % 100 == 0:\n",
    "        print(f\"Epoch [{epoch + 1}/{epochs}], Loss: {loss.item():.4f}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Learned weight: 1.9557, Learned bias: 2.2181\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 400x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predictions for [[4.0], [7.0]]: [[11.04088020324707], [16.907970428466797]]\n"
     ]
    }
   ],
   "source": [
    "# Display the learned parameters\n",
    "[w, b] = model.linear.parameters()\n",
    "print(f\"Learned weight: {w.item():.4f}, Learned bias: {b.item():.4f}\")\n",
    "\n",
    "# Plot the model fit to the train data\n",
    "plt.figure(figsize=(4, 4))\n",
    "plt.scatter(X, y, label='Training Data')\n",
    "plt.plot(X, w.item()*X + b.item(), 'r', label='Model Fit')\n",
    "plt.legend()\n",
    "plt.show()\n",
    "\n",
    "# Testing on new data\n",
    "X_test = torch.tensor([[4.0], [7.0]])\n",
    "with torch.no_grad():\n",
    "    predictions = model(X_test)\n",
    "    print(f\"Predictions for {X_test.tolist()}: {predictions.tolist()}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
